<!--自定义模块实现quill的目录功能-->
<template>
  <div>
    <div ref="quillEditorContainer" style="height: 300px;"></div>
    <div id="table-of-contents">
      <h3>目录</h3>
      <el-button @click="expandAll">切换展开/关闭</el-button>
      <ul>
        <li v-for="item in tableOfContents" :key="item.text">
          <span :class="'toc-level-' + item.level">{{ item.text }}</span>
        </li>
      </ul>
      <!--用树形结构展示目录-->
      <el-tree ref="tree" :data="treeData"
               :indent="10"
               :props="defaultProps"
               node-key="id"
               :highlight-current="true"
               :expand-on-click-node="false"
               @node-click="handleNodeClick"></el-tree>
    </div>
  </div>
</template>

<script>
import Quill from 'quill';
import 'quill/dist/quill.snow.css';

export default {
  data() {
    return {

      quill: null,
      editorContent: '',
      tableOfContents: [],
      //tree
      isExpandedAll: true,
      treeData: [
      ],
      defaultProps: {
        children: 'children',
        label: 'label'
      }
      // tree end
    };
  },
  mounted() {
    const quillEditorContainer = this.$refs.quillEditorContainer;
    this.quill = new Quill(quillEditorContainer, {
      theme: 'snow',
      modules: {
        toolbar: [
          // 字体样式
          ['bold', 'italic', 'underline', 'strike'],
          // 标题快捷键
          [{header: 1}, {header: 2}, {header: 3}, {header: 4}],
          // 标题级别
          [{header: [1, 2, 3, 4, 5, 6, false]}],
          // 字体选择
          [{font: []}],
          // 字体大小
          [{size: ['small', false, 'large', 'huge']}],
          // 文字颜色和背景颜色
          [{color: []}, {background: []}],
          // 引用和代码块
          ['blockquote', 'code-block'],
          // 有序列表和无序列表
          [{list: 'ordered'}, {list: 'bullet'}],
          // 缩进和凸出
          [{indent: '-1'}, {indent: '+1'}],
          // 插入链接、图片和视频
          ['link', 'image', 'video'],
          // 插入表格
          ['table'],
          // 清除格式
          ['clean'],
          // 文本对齐方式
          [{align: ['', 'center', 'right', 'justify']}],
          // 文本方向
          [{'direction': 'rtl'}],
          // 幂等
          [{'script': 'sub'}, {'script': 'super'}],
        ],
      }
    });

    this.quill.on('text-change', this.generateTableOfContents);
  },
  methods: {
    /**
     * 将目录数组转换为树形结构
     * @param data
     * @returns {*[]}
     */
    convertToTree(data) {
      const tree = [];
      let currentParent = null;

      data.forEach((item ,index)=> {
        if (item.level === 1) {
          // 遇到 level 为 1 的，创建新的树节点并作为父节点
          currentParent = {
            label: item.text,
            value: item.text,
            id: index,
            children: []
          };
          tree.push(currentParent);
        }
        else {
          let parent = currentParent;
          while (parent && parent.level < item.level) {
            if (!parent.children) {
              parent.children = [];
            }
            parent = parent.children[parent.children.length - 1];
          }
          if (!parent.children) {
            parent.children = [];
          }
          // 根据 level 创建对应的节点层级
          const newNode = {
            label: item.text,
            value: item.text,
            id: index,
            children: []
          };
          if (item.level === 2) {
            parent.children.push(newNode);
          } else if (item.level === 3) {
            const secondLevelParent = parent.children[parent.children.length - 1];
            if (!secondLevelParent.children) {
              secondLevelParent.children = [];
            }
            secondLevelParent.children.push(newNode);
          } else if (item.level === 4) {
            const secondLevelParent = parent.children[parent.children.length - 1];
            const thirdLevelParent = secondLevelParent.children[secondLevelParent.children.length - 1];
            if (!thirdLevelParent.children) {
              thirdLevelParent.children = [];
            }
            thirdLevelParent.children.push(newNode);
          }
        }
      });

      return tree;
    },
    /**
     * 确保数组的第一个元素是level为1的
     * @param arr
     * @returns {*}
     */
    ensureStartsWithLevel1(arr) {
      if (arr.length > 0 && arr[0].level!== 1) {
        arr.unshift({
          level: 1,
          text: '一级目录'
        });
      }
      return arr;
    },
    /**
     * 处理quill的h1-h6数组
     * @param arr
     * @returns {*[]}
     */
    processArray(arr) {
      let result = [];
      for (let i = 0; i < arr.length; i++) {
        if (arr[i].hasOwnProperty('attributes')) {
          if (i > 0 && arr[i - 1].hasOwnProperty('insert')) {
            arr[i].insert = arr[i - 1].insert + arr[i].insert;
          }
          result.push(arr[i]);
        }
      }
      return result;
    },
    /**
     * 生成目录
     */
    generateTableOfContents() {
      if (this.quill) {
        const contents = this.quill.getContents();
        // const tableOfContents = [];
        let treeCatalog = [];
        // console.log(contents.ops)
        let arr = this.processArray(contents.ops)
        // console.log(arr)
        // 根据h123456来进行目录判断
        arr.forEach((item) => {
          if (item && item.attributes['header'] && item.insert) {
            // tableOfContents.push({
            //   level: item.attributes['header'],
            //   text: item.insert.replace('\n','')
            // });
            // console.log(item.insert)
            // console.log(item.insert.split('\n')[item.insert.split('\n').length-2])
            treeCatalog.push({
              level: item.attributes['header'],
              text: item.insert.split('\n')[item.insert.split('\n').length-2]
            });
          }
        });
        // this.tableOfContents = tableOfContents;
        console.log(treeCatalog)
        treeCatalog = this.ensureStartsWithLevel1(treeCatalog)
        this.treeData = this.convertToTree(treeCatalog);
      }
    },

    /**
     * 点击目录
     * @param data
     */
    handleNodeClick(data) {
      let clickText = data.label
      this.$message.success(data.label)
      console.log(data);
    },

    /**
     *
     */
    expandAll() {
      const tree = this.$refs.tree
      console.log(tree.store['nodesMap'])
      let nodes = tree.store['nodesMap']
      Object.keys(nodes).forEach(key => {
        nodes[key].expanded = !nodes[key].expanded
      })
    },
  }
};
</script>

<style>
/* 可以添加一些样式来美化目录 */
#table-of-contents {
  border: 1px solid #ccc;
  padding: 10px;
}

.toc-level-1 {
  font-size: 18px;
  font-weight: bold;
}

.toc-level-2 {
  font-size: 16px;
}

.toc-level-3 {
  font-size: 14px;
}
</style>